package com.ap.core.jbehave.managerefund;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;

import java.io.IOException;
import java.math.BigDecimal;

import org.hamcrest.CoreMatchers;
import org.jbehave.core.annotations.Given;
import org.jbehave.core.annotations.Then;
import org.jbehave.core.annotations.When;

import com.ap.core.cxf.jaxb.common.APCORE1FaultDetailsType;
import com.ap.core.cxf.jaxb.common.DeliveryType;
import com.ap.core.cxf.jaxb.managepayment.ConfirmPayment1Request;
import com.ap.core.cxf.jaxb.managepayment.ConfirmPayment1Response;
import com.ap.core.cxf.jaxb.managepayment.RetrieveRTP1Request;
import com.ap.core.cxf.jaxb.managepayment.RetrieveRTP1Response;
import com.ap.core.cxf.jaxb.managerefund.RequestRetrieveRefundAccount;
import com.ap.core.cxf.jaxb.managerefund.ResponseRetrieveRefundAccount;
import com.ap.core.cxf.jaxb.managertp.SubmitRTP1Request;
import com.ap.core.cxf.jaxb.managertp.SubmitRTP1Response;
import com.ap.core.cxf.jaxb.managertp.SubmitRTPMessageType;
import com.ap.core.cxf.jaxb.msghdr.MessageType;
import com.ap.core.cxf.jaxb.rtp.TransactionCheckOutType;
import com.ap.core.jbehave.BaseTransitionRTPSteps;
import com.ap.core.jbehave.StoryContext;
import com.ap.core.util.JaxbUtil;
import com.ap.core.util.Nullable;
import com.ap.core.util.TypedKey;
import com.ap.generator.managerefund.RequestRetrieveRefundAccountGeneratorBuilder;
import com.core.ap.wsdl.managepaymentservice_1.ManagePayment1PortType;
import com.core.ap.wsdl.managerefundservice_1.ManageRefund1PortType;
import com.core.ap.wsdl.managerefundservice_1.RetrieveRefundAccount1Fault;
import com.core.ap.wsdl.managertpservice_1.ManageRTP1PortType;
import com.core.ap.wsdl.managertpservice_1.SubmitRTP1Fault;

public class ManageRefundFaultSteps extends BaseTransitionRTPSteps {

	private SubmitRTP1Request submitRTPRequest;
	private SubmitRTP1Response responseRTPType;
	private RetrieveRTP1Request retrieveRTPRequest;
	private RetrieveRTP1Response retrieveRTPResponse;
	private ConfirmPayment1Request confirmPayment1Request;
	private ConfirmPayment1Response confirmPayment1Response;
	private RequestRetrieveRefundAccount requestRetrieveRefundAccount;
	private ResponseRetrieveRefundAccount responseRetrieveRefundAccount;

	/**
	 * @param storyContext
	 */
	public ManageRefundFaultSteps(StoryContext storyContext) {
		super(storyContext);
	}

	@Given("Distributor submited rtp to AP and transaction is succesful")
	public void giveDistributorSubmitsRTPAndPaymentSuccessful()
			throws Exception {

		final ManageRTP1PortType singnedPort = factory
				.getBean(ManageRTP1PortType.class);
		submitRTPRequest = createSubmitRTPRequest(SubmitRTPMessageType.SUBMITRTPFORMOB);
		submitRTPRequest.getRTPSummary().setTxCheckout(
				TransactionCheckOutType.NRMLCHK);
		submitRTPRequest.getRTPSenderInfo().getDistributorInfo()
				.setDistributorId("000001");
		submitRTPRequest.getRTPSenderInfo().getDetailMerchantInfo()
				.getMerchantInfo().setMerchantId("000001");
		submitRTPRequest.getDelivery().setDeliveryType(DeliveryType.DIGDEL);
		submitRTPRequest.getDelivery().setEmailAddress("abc@abc.com");

		LOG.info("Given -  the consumer Bank successfully completed a Faster Payment transaction to the Distributor/Merchant for the value of the purchase using m-com");
		JaxbUtil.newInstance().javaToXML(SubmitRTP1Request.class,
				submitRTPRequest);

		responseRTPType = singnedPort.submitRTP1(submitRTPRequest);

		JaxbUtil.newInstance().javaToXML(SubmitRTP1Response.class,
				responseRTPType);

		/*
		 * storyContext.put(SUBMIT_RTP_RESPONSE,
		 * Nullable.nullable(responseRTPType));
		 */

		doSubmitRTPResponseAssertions(Nullable.nullable(responseRTPType),
				submitRTPRequest);

		final ManagePayment1PortType managePaymentSignedPort = factory
				.getBean(ManagePayment1PortType.class);

		retrieveRTPRequest = createRetrieveRTPRequest();
		
		retrieveRTPRequest.getRequestInfo().setFIId("000001");
		retrieveRTPRequest.getRequestInfo().setFIConsumerId("ntwdcon1");
		
		 if(SubmitRTPMessageType.SUBMITRTPFORMOB == submitRTPRequest.getMsgHdr().getMsgType()){
	            retrieveRTPRequest.getRequestInfo().setApTransactionId(responseRTPType.getResponseInfo().getApTransactionId());
	            retrieveRTPRequest.getRequestInfo().setApTRId(responseRTPType.getResponseInfo().getApTRId());
	            retrieveRTPRequest.getRequestInfo().setBRN(null);
	        }else if(SubmitRTPMessageType.SUBMITRTPFORBRN == submitRTPRequest.getMsgHdr().getMsgType()){
	            retrieveRTPRequest.getRequestInfo().setApTransactionId(null);
	            retrieveRTPRequest.getRequestInfo().setApTRId(null);
	            retrieveRTPRequest.getRequestInfo().setBRN(responseRTPType.getResponseInfo().getBRN());
	        }

		JaxbUtil.newInstance().javaToXML(RetrieveRTP1Request.class,
				retrieveRTPRequest);

		retrieveRTPResponse = managePaymentSignedPort
				.retrieveRTP1(retrieveRTPRequest);

		JaxbUtil.newInstance().javaToXML(RetrieveRTP1Response.class,
				retrieveRTPResponse);

		final ManagePayment1PortType managePayment1PortType = factory
				.getBean(ManagePayment1PortType.class);

		doRetrieveRTPResponseAssertions(
				Nullable.nullable(retrieveRTPResponse.getRTPSummary()),
				Nullable.nullable(retrieveRTPResponse.getRTPSenderInfo()),
				Nullable.nullable(retrieveRTPResponse.getMsgHdr().getMsgType()
						.value()));

		confirmPayment1Request = createConfirmPayment1Request(
				MessageType.CONFIRMPAYMENT, TransactionCheckOutType.NRMLCHK , submitRTPRequest.getDelivery().getDeliveryType());

		confirmPayment1Request.getPaymtDetails().setApTransactionId(
				retrieveRTPRequest.getRequestInfo().getApTransactionId());
		
		confirmPayment1Request.getPaymtDetails().setApTRId(retrieveRTPResponse.getRTPIdentifier().getApTRId());
		
		confirmPayment1Request.getPaymtDetails().setApTRId(retrieveRTPResponse.getRTPIdentifier().getApTRId());

		confirmPayment1Request.getConsumerAcct().setFIId(
				retrieveRTPResponse.getConsumerInfo().getFIId());
		
		confirmPayment1Request.getPaymtDetails().getPaymentStatusInfo().setTotalPaymentReqAmount(retrieveRTPResponse.getRTPSummary().getPaymtAmtInfo().getTotalPaymentReqAmount());

		JaxbUtil.newInstance().javaToXML(ConfirmPayment1Request.class,
				confirmPayment1Request);
		LOG.info("When -  APCore receives the structurally valid CONFIRMPAYMENT request from OSB");

		confirmPayment1Response = managePayment1PortType
				.confirmPayment1(confirmPayment1Request);

		JaxbUtil.newInstance().javaToXML(ConfirmPayment1Response.class,
				confirmPayment1Response);

		doConfirmPaymentResponseAssertions(
				Nullable.nullable(confirmPayment1Response),
				confirmPayment1Request, submitRTPRequest);
	}

	@Given("Distributor want to submit a refund request and get the account details refund amount is zero")
	public void givenDistributorSubmitsNonDisputedRefund() throws IOException {
		requestRetrieveRefundAccount = RequestRetrieveRefundAccountGeneratorBuilder
				.getRetrieveRefundAccountTypeGenerator().build().generate();
		requestRetrieveRefundAccount.getRefundRequestInfo().setDistributorId(
				submitRTPRequest.getRTPSenderInfo().getDistributorInfo()
						.getDistributorId());
		requestRetrieveRefundAccount.getRefundRequestInfo().setMerchantId(
				(submitRTPRequest.getRTPSenderInfo().getDetailMerchantInfo()
						.getMerchantInfo().getMerchantId()));
		requestRetrieveRefundAccount.getRefundRequestInfo().setApTransactionId(
				responseRTPType.getResponseInfo().getApTransactionId());
		requestRetrieveRefundAccount.getRefundRequestInfo().setApTRId(
				(responseRTPType.getResponseInfo().getApTRId()));
		requestRetrieveRefundAccount.getRefundRequestInfo().setRefundAmount(
				new BigDecimal(0));
		JaxbUtil.newInstance().javaToXML(RequestRetrieveRefundAccount.class,
				requestRetrieveRefundAccount);
	}

	@Given("refund amount is zero")
	public void givenDistributorSubmitsDisputedRefund() throws IOException {
		
	}

	@When("Distributor sends a refund request to AP Service")
	public void whenDistributorSendsRefundRequestToAPService()
			throws RetrieveRefundAccount1Fault {
		final ManageRefund1PortType manageRefund1PortType = factory
				.getBean(ManageRefund1PortType.class);
		//responseRetrieveRefundAccount = manageRefund1PortType
		//		.retrieveRefundAccount1(requestRetrieveRefundAccount);



		checkFault(new TypedKey<RetrieveRefundAccount1Fault>("AMOUNT"), manageRefund1PortType, requestRetrieveRefundAccount);
		
	

	}

	@Then("AP Service will respond with SoapFault")
	public void thenAPServiceWillRespondwithSoapFault() {
		for (TypedKey<RetrieveRefundAccount1Fault> key : storyContext.keySet()) {
			APCORE1FaultDetailsType fault = storyContext.get(key).getFaultInfo();
			StringBuilder stringBuilder = new StringBuilder(150);
	    	stringBuilder.append("\n FaultString:"+fault.toString());
	    	stringBuilder.append(" FaultId:"+fault.getFaultid());
	    	stringBuilder.append("\n"+" Errorcode:"+fault.getErrorcode());
	        stringBuilder.append( " ErrorMessage:"+fault.getErrormessage());
	        stringBuilder.append("\n"+" InternalErrorCode:"+fault.getInternalcode());
	        stringBuilder.append(" InternalErrorMessage:"+fault.getInternalmessage());
	        String message = stringBuilder.toString();
			LOG.info("\n\nFault Error Details for "	+key+ " :"+ message+"\n");
			JaxbUtil.newInstance().javaToXML(APCORE1FaultDetailsType.class, fault);

			assertThat("Fault Id is not as expected", false, CoreMatchers.is(equalTo(fault.getFaultid() == null)));
		    assertThat("Error code is not as expected",	false,	CoreMatchers.is(equalTo(fault.getErrorcode() == null)));
		    assertThat("Error Message is not as expected", false, CoreMatchers.is(equalTo(fault.getErrormessage() == null)));
		    assertThat("Internal Code is not as expected", false, CoreMatchers.is(equalTo(fault.getInternalcode() == null)));
		    assertThat("Internal Message is not as expected", false, CoreMatchers.is(equalTo(fault.getInternalmessage() == null)));
		}
	}

	private void checkFault(TypedKey<RetrieveRefundAccount1Fault> FAULT,
			final ManageRefund1PortType manageRefund1PortType,
			RequestRetrieveRefundAccount requestRetrieveRefundAccount) {
		try {
			manageRefund1PortType
					.retrieveRefundAccount1(requestRetrieveRefundAccount);
		} catch (RetrieveRefundAccount1Fault fault) {
			storyContext.put(FAULT, fault);
		}
	}
}
